/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
 */

#include "hellovk.h"
#include "fif.h"
#include <set>
#include <unordered_set>
#include <log.hpp>
#include <AAssetImporter.h>
#include <DescriptorPool.h>
#include <CommandPool.h>
#include <Utils.h>
#include <cstdio>
#include <cstring>

bool vkt::HelloVK::ENABLE_EXTRAPOLATION = false;
namespace vkt {
namespace {
// 控制高频操作的日志输出
static bool s_loggedWaitForFences = false;
static bool s_loggedResetFences = false;
static bool s_loggedResetCommandPool = false;
static bool s_loggedAcquireNextImage = false;
static bool s_loggedBeginCommandBuffer = false;
static bool s_loggedEndCommandBuffer = false;
static bool s_loggedQueueSubmit = false;
static bool s_loggedQueuePresent = false;

[[nodiscard]] const char *ToStringMessageSeverity(VkDebugUtilsMessageSeverityFlagBitsEXT s)
{
    switch (s) {
        case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
            return "VERBOSE";
        case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
            return "ERROR";
        case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
            return "WARNING";
        case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
            return "INFO";
        default:
            return "UNKNOWN";
    }
}

[[nodiscard]] const char *ToStringMessageType(VkDebugUtilsMessageTypeFlagsEXT s)
{
    if (s == (VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
        VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)) {
        return "General | Validation | Performance";
    }

    if (s == (VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)) {
        return "Validation | Performance";
    }

    if (s == (VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)) {
        return "General | Performance";
    }

    if (s == (VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)) {
        return "Performance";
    }

    if (s == (VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT)) {
        return "General | Validation";
    }

    if (s == VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) {
        return "Validation";
    }

    if (s == VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) {
        return "General";
    }

    return "Unknown";
}

VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
    VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
    void * /* pUserData */)
{
    static std::unordered_set<uint32_t> const validationFilter{ // Unspecified message. Safe to ignore it.
        0x00000000U, 0x675DC32EU
    };

    auto const messageID = static_cast<uint32_t>(pCallbackData->messageIdNumber);
    if (validationFilter.contains(messageID)) {
        return VK_FALSE;
    }

    auto ms = ToStringMessageSeverity(messageSeverity);
    auto mt = ToStringMessageType(messageType);
    GOLOGI("[%s: %s]\n%s\n", ms, mt, pCallbackData->pMessage);

    return VK_FALSE;
}

void PopulateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT &createInfo)
{
    constexpr static VkValidationFeatureEnableEXT const validationFeatures[] = {
        VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
        VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT
    };

    constexpr static VkValidationFeaturesEXT validationInfo {
        .sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT,
        .pNext = nullptr,
        .enabledValidationFeatureCount = static_cast<uint32_t>(std::size(validationFeatures)),
        .pEnabledValidationFeatures = validationFeatures,
        .disabledValidationFeatureCount = 0U,
        .pDisabledValidationFeatures = nullptr
    };

    createInfo = {};
    createInfo.pNext = &validationInfo;
    createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;

    createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
        VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;

    createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
        VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;

    createInfo.pfnUserCallback = &DebugCallback;
}

glm::mat4 ConvertGLMMat4ToMat4(glm::mat4 matrix)
{
    // 直接返回glm矩阵，不再需要转换
    return matrix;
}

/**
 * GetPrerotationMatrix handles screen rotation with 3 hardcoded rotation
 * matrices (detailed below). We skip the 180 degrees rotation.
 */
void GetPrerotationMatrix(const VkSurfaceCapabilitiesKHR &capabilities,
    const VkSurfaceTransformFlagBitsKHR &pretransformFlag, std::array<float, 16> &mat)
{
    // mat is initialized to the identity matrix
    mat = { 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1. };
    if (pretransformFlag & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) {
        // mat is set to a 90 deg rotation matrix
        mat = { 0., 1., 0., 0., -1., 0, 0., 0., 0., 0., 1., 0., 0., 0., 0., 1. };
        return;
    }

    if (pretransformFlag & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) {
        // mat is set to 270 deg rotation matrix
        mat = { 0., -1., 0., 0., 1., 0, 0., 0., 0., 0., 1., 0., 0., 0., 0., 1. };
    }
}
} // end of anonymous namespace

void HelloVK::InitVulkan()
{
    CreateInstance();
    CreateSurface();
    PickPhysicalDevice();
    CreateLogicalDeviceAndQueue();
    SetupDebugMessenger();
    EstablishDisplaySizeIdentity();
    CreateSwapChain();
    CreateImageViews();
    FGInitDevice();
    FGCreateCommandPool();
    FGCreateColorResources();
    FGCreateDepthResources();
    OHTestApp::DescriptorPool::Instance().Init();
    FGCreateSwapchainSyncObjects();
    FGInitUIRenderer();
    FGInitMainSceneRenderer();

    // API 冒烟测试
    RunApiSmokeTestsOnce();

    m_initialized = true;
}

void HelloVK::RunApiSmokeTestsOnce()
{
    static bool s_ran = false; if (s_ran) return; s_ran = true;

    VkInstance instance = m_instance; VkDevice device = m_device;

    // 成功日志只打印一次
    static bool logged_vkGetInstanceProcAddr = false;
    static bool logged_vkEnumerateInstanceLayerProperties = false;
    static bool logged_vkFreeDescriptorSets = false;
    static bool logged_vkDestroyRenderPass = false;
    static bool logged_vkDestroySampler = false;
    static bool logged_vkDestroyBuffer = false;
    static bool logged_vkDestroyPipeline = false;
    static bool logged_vkDestroyPipelineLayout = false;
    static bool logged_vkCmdBeginQuery = false;
    static bool logged_vkCmdBeginRendering = false;
    static bool logged_vkCmdBindIndexBuffer = false;
    static bool logged_vkCmdBlitImage = false;
    static bool logged_vkCmdClearAttachments = false;
    static bool logged_vkCmdClearColorImage = false;
    static bool logged_vkCmdClearDepthStencilImage = false;
    static bool logged_vkCmdCopyBuffer = false;
    static bool logged_vkCmdCopyImage = false;
    static bool logged_vkCmdCopyImageToBuffer = false;
    static bool logged_vkCmdCopyQueryPoolResults = false;
    static bool logged_vkCmdDispatch = false;
    static bool logged_vkCmdDispatchBase = false;
    static bool logged_vkCmdDispatchIndirect = false;
    static bool logged_vkCmdExecuteCommands = false;
    static bool logged_vkCmdFillBuffer = false;
    static bool logged_vkCmdNextSubpass = false;
    static bool logged_vkCmdPushConstants = false;
    static bool logged_vkCmdResetEvent = false;
    static bool logged_vkCmdEndQuery = false;
    static bool logged_vkCmdEndRendering = false;
    static bool logged_vkCreateShaderModule = false;
    static bool logged_vkDestroyShaderModule = false;
    static bool logged_vkCreateComputePipelines = false;

    // vkGetInstanceProcAddr
    // 某些实现仅在 instance 为 nullptr 时，才为实例无关函数返回入口；为兼容性，先以 nullptr 查询，再以有效 instance 兜底
    PFN_vkVoidFunction pEnumExtNull = vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceExtensionProperties");
    PFN_vkVoidFunction pEnumExtInst = vkGetInstanceProcAddr(instance, "vkEnumerateInstanceExtensionProperties");
    if (pEnumExtNull || pEnumExtInst) {
        if (!logged_vkGetInstanceProcAddr) { GOLOGW("vkGetInstanceProcAddr completed successfully"); logged_vkGetInstanceProcAddr = true; }
    } else {
        GOLOGE("vkGetInstanceProcAddr returned null for vkEnumerateInstanceExtensionProperties (tried nullptr and instance)");
    }

    // vkEnumerateInstanceLayerProperties（count + data）
    uint32_t layerCount = 0; VkResult r = vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
    if (r == VK_SUCCESS) {
        std::vector<VkLayerProperties> layers(layerCount);
        r = vkEnumerateInstanceLayerProperties(&layerCount, layers.data());
        if (r == VK_SUCCESS) { if (!logged_vkEnumerateInstanceLayerProperties) { GOLOGW("vkEnumerateInstanceLayerProperties completed successfully"); logged_vkEnumerateInstanceLayerProperties = true; } }
        else { GOLOGE("vkEnumerateInstanceLayerProperties (data) failed: %d", r); }
    } else { GOLOGE("vkEnumerateInstanceLayerProperties (count) failed: %d", r); }

    // 描述符集布局 + 管线布局（用于 vkFreeDescriptorSets / vkDestroyPipelineLayout）
    VkDescriptorSetLayout dsl = VK_NULL_HANDLE; {
        VkDescriptorSetLayoutBinding b{}; b.binding = 0; b.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; b.descriptorCount = 1; b.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
        VkDescriptorSetLayoutCreateInfo ci{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; ci.bindingCount = 1; ci.pBindings = &b;
        VkResult cr = vkCreateDescriptorSetLayout(device, &ci, nullptr, &dsl);
        if (cr != VK_SUCCESS) { GOLOGE("vkCreateDescriptorSetLayout failed: %d", cr); }
    }
    VkPipelineLayout pl = VK_NULL_HANDLE; {
        VkPipelineLayoutCreateInfo pci{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
        pci.setLayoutCount = dsl ? 1u : 0u; pci.pSetLayouts = dsl ? &dsl : nullptr;
        VkResult cr = vkCreatePipelineLayout(device, &pci, nullptr, &pl);
        if (cr != VK_SUCCESS) { GOLOGE("vkCreatePipelineLayout failed: %d", cr); }
    }

    // 分配并释放一个描述符集（vkFreeDescriptorSets）
    if (auto pool = OHTestApp::DescriptorPool::Instance().GetNativeDescriptorPool(); pool != VK_NULL_HANDLE && dsl != VK_NULL_HANDLE) {
        VkDescriptorSet ds = VK_NULL_HANDLE;
        VkDescriptorSetAllocateInfo ai{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO }; ai.descriptorPool = pool; ai.descriptorSetCount = 1; ai.pSetLayouts = &dsl;
        VkResult ar = vkAllocateDescriptorSets(device, &ai, &ds);
        if (ar == VK_SUCCESS) {
            VkResult fr = vkFreeDescriptorSets(device, pool, 1, &ds);
            if (fr == VK_SUCCESS) { if (!logged_vkFreeDescriptorSets) { GOLOGW("vkFreeDescriptorSets completed successfully"); logged_vkFreeDescriptorSets = true; } }
            else { GOLOGE("vkFreeDescriptorSets failed: %d", fr); }
        } else { GOLOGE("vkAllocateDescriptorSets failed: %d", ar); }
    } else { GOLOGE("DescriptorPool or DescriptorSetLayout is null; skip vkFreeDescriptorSets"); }

    // vkDestroyPipelineLayout
    if (pl) { vkDestroyPipelineLayout(device, pl, nullptr); if (!logged_vkDestroyPipelineLayout) { GOLOGW("vkDestroyPipelineLayout completed successfully"); logged_vkDestroyPipelineLayout = true; } pl = VK_NULL_HANDLE; }
    else { GOLOGE("PipelineLayout is null; skip vkDestroyPipelineLayout"); }
    // vkDestroySampler（先创建再销毁）
    {
        VkSamplerCreateInfo sci{ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
        sci.magFilter = VK_FILTER_LINEAR; sci.minFilter = VK_FILTER_LINEAR; sci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
        sci.addressModeU = sci.addressModeV = sci.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
        VkSampler sampler = VK_NULL_HANDLE; VkResult sr = vkCreateSampler(device, &sci, nullptr, &sampler);
        if (sr == VK_SUCCESS) { 
            if (sampler != VK_NULL_HANDLE) {
                vkDestroySampler(device, sampler, nullptr); 
                if (!logged_vkDestroySampler) { GOLOGW("vkDestroySampler completed successfully"); logged_vkDestroySampler = true; }
            } else {
                GOLOGE("Sampler handle is null; skip vkDestroySampler");
            }
        } else { 
            GOLOGE("vkCreateSampler failed: %d", sr); 
        }
    }

    //  vkUnmapMemory + vkDestroyBuffer：通过 Buffer 封装（手动 flush）
    {
        OHTestApp::Buffer buf; OHTestApp::Buffer::BufferDescriptor bd{ "SmokeBuf", 16u, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT };
        if (buf.Init(bd)) {
            uint32_t v = 0xDEADBEEF; buf.UpdateData(&v, sizeof(v));
            buf.Unmap(nullptr); // Buffer 内部保证 vkUnmapMemory 成功只记录一次
            buf.Destroy(); 
            if (!logged_vkDestroyBuffer) { GOLOGW("vkDestroyBuffer completed successfully"); logged_vkDestroyBuffer = true; }
        } else {
            GOLOGE("Buffer initialization failed; skip vkDestroyBuffer test");
        }
    }

    // vkDestroyRenderPass：创建最小 render pass 后销毁
    {
        VkAttachmentDescription color{}; color.format = m_swapChainImageFormat; color.samples = VK_SAMPLE_COUNT_1_BIT; color.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; color.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; color.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; color.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
        VkAttachmentReference colorRef{ 0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
        VkSubpassDescription sub{}; sub.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; sub.colorAttachmentCount = 1; sub.pColorAttachments = &colorRef;
        VkRenderPassCreateInfo rpci{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO }; rpci.attachmentCount = 1; rpci.pAttachments = &color; rpci.subpassCount = 1; rpci.pSubpasses = &sub;
        VkRenderPass rp = VK_NULL_HANDLE; VkResult rr = vkCreateRenderPass(device, &rpci, nullptr, &rp);
        if (rr == VK_SUCCESS) { vkDestroyRenderPass(device, rp, nullptr); if (!logged_vkDestroyRenderPass) { GOLOGW("vkDestroyRenderPass completed successfully"); logged_vkDestroyRenderPass = true; } }
        else { GOLOGE("vkCreateRenderPass failed: %d", rr); }
    }

    // vkDestroyPipeline：创建真实计算管线后销毁（避免图形管线的着色器编译问题）
    {
        GOLOGI("Testing vkDestroyPipeline with real compute pipeline...");
        
        // 计算管线测试中的最小着色器
        const uint32_t computeSpv[] = {
            0x07230203, 0x00010000, 0x0008000a, 0x00000006, 0x00000000, 0x00020011, 0x00000001, 0x0006000b,
            0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001,
            0x0005000f, 0x00000005, 0x00000004, 0x6e69616d, 0x00000000, 0x00060010, 0x00000004, 0x00000011,
            0x00000001, 0x00000001, 0x00000001, 0x00030003, 0x00000002, 0x000001c2, 0x00040005, 0x00000004,
            0x6e69616d, 0x00000000, 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00050036,
            0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x000100fd, 0x00010038
        };
        
        VkShaderModuleCreateInfo smci{ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
        smci.codeSize = sizeof(computeSpv); 
        smci.pCode = computeSpv;
        VkShaderModule testShader = VK_NULL_HANDLE;
        VkResult sr = vkCreateShaderModule(device, &smci, nullptr, &testShader);
        
        if (sr == VK_SUCCESS && testShader != VK_NULL_HANDLE) {
            VkPipelineLayoutCreateInfo plci{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
            VkPipelineLayout testLayout = VK_NULL_HANDLE;
            VkResult plr = vkCreatePipelineLayout(device, &plci, nullptr, &testLayout);
            
            if (plr == VK_SUCCESS && testLayout != VK_NULL_HANDLE) {
                VkComputePipelineCreateInfo cpci{ VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
                cpci.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
                cpci.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
                cpci.stage.module = testShader;
                cpci.stage.pName = "main";
                cpci.layout = testLayout;
                
                VkPipeline testPipeline = VK_NULL_HANDLE;
                GOLOGI("Calling vkCreateComputePipelines for vkDestroyPipeline test...");
                VkResult cpr = vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &cpci, nullptr, &testPipeline);
                
                if (cpr == VK_SUCCESS) {
                    if (!logged_vkCreateComputePipelines) {
                        GOLOGW("vkCreateComputePipelines completed successfully");
                        logged_vkCreateComputePipelines = true;
                    }
                    
                    if (testPipeline != VK_NULL_HANDLE) {
                        GOLOGI("Calling vkDestroyPipeline with real compute pipeline...");
                        vkDestroyPipeline(device, testPipeline, nullptr);
                        if (!logged_vkDestroyPipeline) {
                            GOLOGW("vkDestroyPipeline (real compute pipeline) completed successfully");
                            logged_vkDestroyPipeline = true;
                        }
                    } else {
                        GOLOGE("vkCreateComputePipelines succeeded but returned null pipeline handle");
                    }
                } else {
                    GOLOGE("vkCreateComputePipelines for vkDestroyPipeline test failed: %d", cpr);
                }
                
                vkDestroyPipelineLayout(device, testLayout, nullptr);
            } else {
                GOLOGE("vkCreatePipelineLayout for vkDestroyPipeline test failed: %d", plr);
            }
            
            vkDestroyShaderModule(device, testShader, nullptr);
        } else {
            GOLOGE("vkCreateShaderModule for vkDestroyPipeline test failed: %d", sr);
        }
    }

    // vkCmdBeginQuery：一次性命令缓冲实际执行 reset/begin/end 并提交
    {
        VkQueryPool qp = VK_NULL_HANDLE; 
        { 
            VkQueryPoolCreateInfo qci{ VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO }; 
            qci.queryType = VK_QUERY_TYPE_OCCLUSION; 
            qci.queryCount = 2; 
            GOLOGI("Calling vkCreateQueryPool for vkCmdBeginQuery test...");
            VkResult qr = vkCreateQueryPool(device, &qci, nullptr, &qp); 
            if (qr != VK_SUCCESS) { 
                GOLOGE("vkCreateQueryPool failed: %d", qr); 
                qp = VK_NULL_HANDLE; 
            } else {
                GOLOGW("vkCreateQueryPool completed successfully");
            }
        }
        if (qp) {
            VkCommandBuffer cmd = OHTestApp::BeginSingleTimeCommands();
            GOLOGI("Calling vkCmdResetQueryPool...");
            vkCmdResetQueryPool(cmd, qp, 0, 2);
            GOLOGI("Calling vkCmdBeginQuery...");
            vkCmdBeginQuery(cmd, qp, 0, 0);
            GOLOGI("Calling vkCmdEndQuery...");
            vkCmdEndQuery(cmd, qp, 0);
            OHTestApp::EndSingleTimeCommands(cmd);
            if (!logged_vkCmdBeginQuery) { GOLOGW("vkCmdBeginQuery completed successfully"); logged_vkCmdBeginQuery = true; }
            GOLOGI("Calling vkDestroyQueryPool...");
            vkDestroyQueryPool(device, qp, nullptr);
            GOLOGW("vkDestroyQueryPool completed successfully");
        } else {
            GOLOGE("QueryPool is null; skip vkCmdBeginQuery test");
        }
    }
    
    {
        // 资源准备：小尺寸颜色图像(作SRC/DST/Attachment)、深度图像、拷贝用缓冲与索引缓冲
        const uint32_t W = 32, H = 32;
        VkFormat colorFmt = m_swapChainImageFormat; // 已验证可做color attachment
        VkFormat depthFmt = OHTestApp::Device::Instance().FindDepthFormat();
        // 按实际格式决定是否包含 STENCIL 位，避免非法 aspect 组合
        VkImageAspectFlags depthAspect = VK_IMAGE_ASPECT_DEPTH_BIT;
        if (depthFmt == VK_FORMAT_D32_SFLOAT_S8_UINT || depthFmt == VK_FORMAT_D24_UNORM_S8_UINT) {
            depthAspect |= VK_IMAGE_ASPECT_STENCIL_BIT;
        }

        OHTestApp::Image colorSrc, colorDst, depthImg;
        colorSrc.Init(OHTestApp::Image::ImageDescriptor()
            .Name("SmokeColorSrc").Width(W).Height(H).Format(colorFmt)
            .Tile(VK_IMAGE_TILING_OPTIMAL)
            .MemProperties(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
            .Usage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT));
        colorDst.Init(OHTestApp::Image::ImageDescriptor()
            .Name("SmokeColorDst").Width(W).Height(H).Format(colorFmt)
            .Tile(VK_IMAGE_TILING_OPTIMAL)
            .MemProperties(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
            .Usage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT));
        depthImg.Init(OHTestApp::Image::ImageDescriptor()
            .Name("SmokeDepth").Width(W).Height(H).Format(depthFmt)
            .Tile(VK_IMAGE_TILING_OPTIMAL)
            .MemProperties(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
            .Usage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT));
        VkImageView colorSrcView = colorSrc.GetNativeImageView();
        VkImageView colorDstView = colorDst.GetNativeImageView();
        (void)colorSrcView; // src view暂不直接用

        // 拷贝用缓冲
        OHTestApp::Buffer bufDst; OHTestApp::Buffer::BufferDescriptor bdDst{ "SmokeCopyDstBuf", W*H*4u, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT };
        bufDst.Init(bdDst);
        
        // 索引缓冲
        OHTestApp::Buffer indexBuf; OHTestApp::Buffer::BufferDescriptor ibDesc{ "SmokeIndexBuf", 6u * sizeof(uint16_t), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT };
        if (indexBuf.Init(ibDesc)) {
            uint16_t idx[6] = {0,1,2,2,3,0}; indexBuf.UpdateData(idx, sizeof(idx));
        }

        // 另备一个小缓冲做 buffer->buffer copy 源
        OHTestApp::Buffer bufSrc; OHTestApp::Buffer::BufferDescriptor bdSrc{ "SmokeCopySrcBuf", 64u, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT };
        if (bufSrc.Init(bdSrc)) {
            uint8_t pattern[64]; for (int i=0;i<64;++i) pattern[i]=static_cast<uint8_t>(i); bufSrc.UpdateData(pattern, sizeof(pattern));
        }

        // 开始一次性命令缓冲
        VkCommandBuffer cmd = OHTestApp::BeginSingleTimeCommands();

        // 布局转换：供清除/复制/混合
        OHTestApp::RecordImageLayoutTransitionCommands(
            cmd, colorSrc.GetNativeImage(), VK_IMAGE_ASPECT_COLOR_BIT,
            VK_IMAGE_LAYOUT_UNDEFINED, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
            VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
        OHTestApp::RecordImageLayoutTransitionCommands(
            cmd, colorDst.GetNativeImage(), VK_IMAGE_ASPECT_COLOR_BIT,
            VK_IMAGE_LAYOUT_UNDEFINED, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
        OHTestApp::RecordImageLayoutTransitionCommands(
            cmd, depthImg.GetNativeImage(), depthAspect,
            VK_IMAGE_LAYOUT_UNDEFINED, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);

        // vkCmdClearColorImage
        VkClearColorValue clearColor{}; clearColor.float32[0]=0.2f; clearColor.float32[1]=0.4f; clearColor.float32[2]=0.6f; clearColor.float32[3]=1.0f;
        VkImageSubresourceRange clrRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
        vkCmdClearColorImage(cmd, colorDst.GetNativeImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1, &clrRange);
        if (!logged_vkCmdClearColorImage) { GOLOGW("vkCmdClearColorImage completed successfully"); logged_vkCmdClearColorImage = true; }

        // vkCmdClearDepthStencilImage
        VkClearDepthStencilValue ds{1.0f, 0};
        VkImageSubresourceRange dsRange{ depthAspect, 0, 1, 0, 1 };
        vkCmdClearDepthStencilImage(cmd, depthImg.GetNativeImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &ds, 1, &dsRange);
        if (!logged_vkCmdClearDepthStencilImage) { GOLOGW("vkCmdClearDepthStencilImage completed successfully"); logged_vkCmdClearDepthStencilImage = true; }

        // vkCmdBlitImage（src: TRANSFER_SRC_OPTIMAL, dst: TRANSFER_DST_OPTIMAL）
        VkImageBlit blit{};
        blit.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
        blit.srcOffsets[0] = {0,0,0}; blit.srcOffsets[1] = { (int32_t)W, (int32_t)H, 1 };
        blit.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
        blit.dstOffsets[0] = {0,0,0}; blit.dstOffsets[1] = { (int32_t)W, (int32_t)H, 1 };
        vkCmdBlitImage(cmd,
            colorSrc.GetNativeImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
            colorDst.GetNativeImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
            1, &blit, VK_FILTER_NEAREST);
        if (!logged_vkCmdBlitImage) { GOLOGW("vkCmdBlitImage completed successfully"); logged_vkCmdBlitImage = true; }

        // vkCmdCopyImage（再复制一次）
        VkImageCopy ic{};
        ic.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
        ic.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
        ic.extent = { W, H, 1 };
        vkCmdCopyImage(cmd,
            colorSrc.GetNativeImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
            colorDst.GetNativeImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
            1, &ic);
        if (!logged_vkCmdCopyImage) { GOLOGW("vkCmdCopyImage completed successfully"); logged_vkCmdCopyImage = true; }

        // vkCmdCopyImageToBuffer（把colorDst拷贝到缓冲）
        VkBufferImageCopy b2{}; b2.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; b2.imageExtent = { W, H, 1 };
        vkCmdCopyImageToBuffer(cmd, colorDst.GetNativeImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, bufDst.GetNativeBuffer(), 1, &b2);
        if (!logged_vkCmdCopyImageToBuffer) { GOLOGW("vkCmdCopyImageToBuffer completed successfully"); logged_vkCmdCopyImageToBuffer = true; }

        // vkCmdCopyBuffer（把bufSrc内容拷贝到bufDst前64字节）
        VkBufferCopy bcopy{}; bcopy.srcOffset = 0; bcopy.dstOffset = 0; bcopy.size = 64;
        vkCmdCopyBuffer(cmd, bufSrc.GetNativeBuffer(), bufDst.GetNativeBuffer(), 1, &bcopy);
        if (!logged_vkCmdCopyBuffer) { GOLOGW("vkCmdCopyBuffer completed successfully"); logged_vkCmdCopyBuffer = true; }

        // vkCmdBindIndexBuffer
        vkCmdBindIndexBuffer(cmd, indexBuf.GetNativeBuffer(), 0, VK_INDEX_TYPE_UINT16);
        if (!logged_vkCmdBindIndexBuffer) { GOLOGW("vkCmdBindIndexBuffer completed successfully"); logged_vkCmdBindIndexBuffer = true; }

        // 动态渲染测试：vkCmdBeginRendering + vkCmdClearAttachments
        // 注意：此处的 vkCmdBeginRendering 和 vkCmdEndRendering 需要 Vulkan 1.3 或 VK_KHR_dynamic_rendering 扩展支持
        // 但是当前测试设备并不支持以上两条路径，所以此处为盲测
        // 先把colorDst切到 COLOR_ATTACHMENT_OPTIMAL 以匹配附件布局
        OHTestApp::RecordImageLayoutTransitionCommands(
            cmd, colorDst.GetNativeImage(), VK_IMAGE_ASPECT_COLOR_BIT,
            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
            VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);

        VkRenderingAttachmentInfo colorAttach{ VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO };
        colorAttach.imageView = colorDstView;
        colorAttach.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
        colorAttach.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
        colorAttach.storeOp = VK_ATTACHMENT_STORE_OP_STORE;

        VkRenderingInfo ri{ VK_STRUCTURE_TYPE_RENDERING_INFO };
        ri.renderArea = { {0,0}, { W, H } };
        ri.layerCount = 1;
        ri.colorAttachmentCount = 1; ri.pColorAttachments = &colorAttach;

        // 通过设备地址获取函数指针，兼容 1.3 核心或 KHR 扩展两种路径
        PFN_vkCmdBeginRendering pBegin = reinterpret_cast<PFN_vkCmdBeginRendering>(vkGetDeviceProcAddr(device, "vkCmdBeginRendering"));
        PFN_vkCmdBeginRenderingKHR pBeginKHR = reinterpret_cast<PFN_vkCmdBeginRenderingKHR>(vkGetDeviceProcAddr(device, "vkCmdBeginRenderingKHR"));
        PFN_vkCmdEndRendering pEnd = reinterpret_cast<PFN_vkCmdEndRendering>(vkGetDeviceProcAddr(device, "vkCmdEndRendering"));
        PFN_vkCmdEndRenderingKHR pEndKHR = reinterpret_cast<PFN_vkCmdEndRenderingKHR>(vkGetDeviceProcAddr(device, "vkCmdEndRenderingKHR"));
    
        if (!pBegin && !pBeginKHR) {
            GOLOGE("vkCmdBeginRendering: NOT AVAILABLE (neither core nor KHR extension found)");
        }
        if (!pEnd && !pEndKHR) {
            GOLOGE("vkCmdEndRendering: NOT AVAILABLE (neither core nor KHR extension found)");
        }

        if ((pBegin || pBeginKHR) && (pEnd || pEndKHR) && colorDstView != VK_NULL_HANDLE) {
            if (pBegin) { 
                pBegin(cmd, &ri); 
                if (!logged_vkCmdBeginRendering) { GOLOGW("vkCmdBeginRendering completed successfully (Vulkan 1.3 core)"); logged_vkCmdBeginRendering = true; }
            }
            else { 
                pBeginKHR(cmd, reinterpret_cast<const VkRenderingInfoKHR*>(&ri)); 
                if (!logged_vkCmdBeginRendering) { GOLOGW("vkCmdBeginRendering completed successfully (VK_KHR_dynamic_rendering)"); logged_vkCmdBeginRendering = true; }
            }

            VkClearAttachment ca{}; ca.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; ca.colorAttachment = 0; ca.clearValue.color = {{0.9f,0.1f,0.1f,1.0f}};
            VkClearRect cr{}; cr.rect = { {4,4}, { W-8, H-8 } }; cr.baseArrayLayer = 0; cr.layerCount = 1;
            vkCmdClearAttachments(cmd, 1, &ca, 1, &cr);
            if (!logged_vkCmdClearAttachments) { GOLOGW("vkCmdClearAttachments completed successfully"); logged_vkCmdClearAttachments = true; }

            if (pEnd) { 
                pEnd(cmd); 
                if (!logged_vkCmdEndRendering) { GOLOGW("vkCmdEndRendering completed successfully (Vulkan 1.3 core)"); logged_vkCmdEndRendering = true; }
            } else { 
                pEndKHR(cmd); 
                if (!logged_vkCmdEndRendering) { GOLOGW("vkCmdEndRendering completed successfully (VK_KHR_dynamic_rendering)"); logged_vkCmdEndRendering = true; }
            }
        } else {
            // 若不支持两个api则fallback: 使用最小 render pass/framebuffer 进入渲染范围后调用 vkCmdClearAttachments
            GOLOGW("vkCmdBeginRendering/vkCmdEndRendering: Using fallback render pass (dynamic rendering not available)");
            if (colorDstView == VK_NULL_HANDLE) {
                GOLOGE("color attachment view is null; fallback render pass cannot be created");
            } else {
                VkAttachmentDescription color{};
                color.format = colorFmt;
                color.samples = VK_SAMPLE_COUNT_1_BIT;
                color.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
                color.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
                color.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
                color.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
                color.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
                color.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

                VkAttachmentReference colorRef{ 0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
                VkSubpassDescription sub{};
                sub.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
                sub.colorAttachmentCount = 1;
                sub.pColorAttachments = &colorRef;

                VkRenderPassCreateInfo rpci{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
                rpci.attachmentCount = 1;
                rpci.pAttachments = &color;
                rpci.subpassCount = 1;
                rpci.pSubpasses = &sub;

                VkRenderPass rp = VK_NULL_HANDLE;
                VkResult rr = vkCreateRenderPass(device, &rpci, nullptr, &rp);
                if (rr != VK_SUCCESS) {
                    GOLOGE("vkCreateRenderPass (fallback) failed: %d", rr);
                } else {
                    VkImageView attachments[] = { colorDstView };
                    VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
                    fbci.renderPass = rp;
                    fbci.attachmentCount = 1;
                    fbci.pAttachments = attachments;
                    fbci.width = W; fbci.height = H; fbci.layers = 1;
                    VkFramebuffer fb = VK_NULL_HANDLE;
                    VkResult fr = vkCreateFramebuffer(device, &fbci, nullptr, &fb);
                    if (fr != VK_SUCCESS) {
                        GOLOGE("vkCreateFramebuffer (fallback) failed: %d", fr);
                        vkDestroyRenderPass(device, rp, nullptr);
                    } else {
                        VkRenderPassBeginInfo rbi{ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
                        rbi.renderPass = rp;
                        rbi.framebuffer = fb;
                        rbi.renderArea.offset = {0,0};
                        rbi.renderArea.extent = { W, H };
                        rbi.clearValueCount = 0; rbi.pClearValues = nullptr; // 使用 ClearAttachments 清除

                        vkCmdBeginRenderPass(cmd, &rbi, VK_SUBPASS_CONTENTS_INLINE);
                        VkClearAttachment ca{}; ca.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; ca.colorAttachment = 0; ca.clearValue.color = {{0.9f,0.1f,0.1f,1.0f}};
                        VkClearRect cr{}; cr.rect = { {4,4}, { W-8, H-8 } }; cr.baseArrayLayer = 0; cr.layerCount = 1;
                        vkCmdClearAttachments(cmd, 1, &ca, 1, &cr);
                        if (!logged_vkCmdClearAttachments) { GOLOGW("vkCmdClearAttachments completed successfully"); logged_vkCmdClearAttachments = true; }
                        vkCmdEndRenderPass(cmd);

                        vkDestroyFramebuffer(device, fb, nullptr);
                        vkDestroyRenderPass(device, rp, nullptr);
                    }
                }
            }
        }

        // 查询池结果拷贝：vkCmdCopyQueryPoolResults
        VkQueryPool qp2 = VK_NULL_HANDLE; { VkQueryPoolCreateInfo qci{ VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO }; qci.queryType = VK_QUERY_TYPE_OCCLUSION; qci.queryCount = 2; VkResult qr = vkCreateQueryPool(device, &qci, nullptr, &qp2); if (qr != VK_SUCCESS) { GOLOGE("vkCreateQueryPool failed: %d", qr); } }
        if (qp2) {
            vkCmdResetQueryPool(cmd, qp2, 0, 2);
            vkCmdBeginQuery(cmd, qp2, 0, 0);
            vkCmdEndQuery(cmd, qp2, 0);
            vkCmdCopyQueryPoolResults(cmd, qp2, 0, 1, bufDst.GetNativeBuffer(), 0, sizeof(uint64_t), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
        }

        OHTestApp::EndSingleTimeCommands(cmd);

        // 提交成功且未触发错误视为上述API均执行成功
        if (!logged_vkCmdCopyQueryPoolResults) { GOLOGW("vkCmdCopyQueryPoolResults completed successfully"); logged_vkCmdCopyQueryPoolResults = true; }

        if (qp2) { vkDestroyQueryPool(device, qp2, nullptr); }

        // 清理局部资源
        colorSrc.Destroy(); colorDst.Destroy(); depthImg.Destroy();
        bufSrc.Destroy(); indexBuf.Destroy(); bufDst.Destroy();
    }

    {
        // 创建简单的计算着色器（最小有效 SPIR-V）
        // 对应 GLSL: #version 450; layout(local_size_x=1) in; void main() {}
        const uint32_t computeSpv[] = {
            0x07230203, 0x00010000, 0x0008000a, 0x00000006, 0x00000000, 0x00020011, 0x00000001, 0x0006000b,
            0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, 0x00000000, 0x00000001,
            0x0005000f, 0x00000005, 0x00000004, 0x6e69616d, 0x00000000, 0x00060010, 0x00000004, 0x00000011,
            0x00000001, 0x00000001, 0x00000001, 0x00030003, 0x00000002, 0x000001c2, 0x00040005, 0x00000004,
            0x6e69616d, 0x00000000, 0x00020013, 0x00000002, 0x00030021, 0x00000003, 0x00000002, 0x00050036,
            0x00000002, 0x00000004, 0x00000000, 0x00000003, 0x000200f8, 0x00000005, 0x000100fd, 0x00010038
        };

        VkShaderModuleCreateInfo smci{ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
        smci.codeSize = sizeof(computeSpv); smci.pCode = computeSpv;
        VkShaderModule compShader = VK_NULL_HANDLE; 
        VkResult sr = vkCreateShaderModule(device, &smci, nullptr, &compShader);
        if (sr != VK_SUCCESS) { 
            GOLOGE("vkCreateShaderModule (compute) failed: %d", sr);
        } else {
            if (!logged_vkCreateShaderModule) { 
                GOLOGW("vkCreateShaderModule (compute) completed successfully"); 
                logged_vkCreateShaderModule = true; 
            }
        }

        if (compShader) {
            // 创建计算管线布局
            VkPipelineLayoutCreateInfo plci{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
            VkPipelineLayout compPipelineLayout = VK_NULL_HANDLE;
            VkResult plr = vkCreatePipelineLayout(device, &plci, nullptr, &compPipelineLayout);
            if (plr != VK_SUCCESS) { GOLOGE("vkCreatePipelineLayout (compute) failed: %d", plr); }

            if (compPipelineLayout) {
                // 创建计算管线
                VkComputePipelineCreateInfo cpci{ VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
                cpci.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
                cpci.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
                cpci.stage.module = compShader;
                cpci.stage.pName = "main";
                cpci.layout = compPipelineLayout;
                VkPipeline compPipeline = VK_NULL_HANDLE;
                VkResult cpr = vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &cpci, nullptr, &compPipeline);
                if (cpr != VK_SUCCESS) { GOLOGE("vkCreateComputePipelines failed: %d", cpr); }

                if (compPipeline) {
                    // 创建间接调度缓冲（用于 vkCmdDispatchIndirect）
                    OHTestApp::Buffer indirectBuf;
                    OHTestApp::Buffer::BufferDescriptor ibDesc{ "SmokeIndirectDispatchBuf", sizeof(VkDispatchIndirectCommand), 
                        VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT };
                    if (indirectBuf.Init(ibDesc)) {
                        VkDispatchIndirectCommand indCmd{ 1, 1, 1 };
                        indirectBuf.UpdateData(&indCmd, sizeof(indCmd));
                    }

                    // 开始一次性命令缓冲
                    VkCommandBuffer cmd = OHTestApp::BeginSingleTimeCommands();

                    vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, compPipeline);

                    // 测试 vkCmdDispatch
                    vkCmdDispatch(cmd, 1, 1, 1);
                    if (!logged_vkCmdDispatch) { GOLOGW("vkCmdDispatch completed successfully"); logged_vkCmdDispatch = true; }

                    // 测试 vkCmdDispatchBase
                    PFN_vkCmdDispatchBase pDispatchBase = reinterpret_cast<PFN_vkCmdDispatchBase>(vkGetDeviceProcAddr(device, "vkCmdDispatchBase"));
                    if (pDispatchBase) {
                        pDispatchBase(cmd, 0, 0, 0, 1, 1, 1);
                        if (!logged_vkCmdDispatchBase) { GOLOGW("vkCmdDispatchBase completed successfully"); logged_vkCmdDispatchBase = true; }
                    } else {
                        // 尝试 KHR 扩展版本
                        PFN_vkCmdDispatchBaseKHR pDispatchBaseKHR = reinterpret_cast<PFN_vkCmdDispatchBaseKHR>(vkGetDeviceProcAddr(device, "vkCmdDispatchBaseKHR"));
                        if (pDispatchBaseKHR) {
                            pDispatchBaseKHR(cmd, 0, 0, 0, 1, 1, 1);
                            if (!logged_vkCmdDispatchBase) { GOLOGW("vkCmdDispatchBase completed successfully"); logged_vkCmdDispatchBase = true; }
                        } else {
                            GOLOGE("vkCmdDispatchBase and vkCmdDispatchBaseKHR not available");
                        }
                    }

                    // 测试 vkCmdDispatchIndirect
                    if (indirectBuf.GetNativeBuffer() != VK_NULL_HANDLE) {
                        vkCmdDispatchIndirect(cmd, indirectBuf.GetNativeBuffer(), 0);
                        if (!logged_vkCmdDispatchIndirect) { GOLOGW("vkCmdDispatchIndirect completed successfully"); logged_vkCmdDispatchIndirect = true; }
                    } else {
                        GOLOGE("Indirect dispatch buffer is null; skip vkCmdDispatchIndirect");
                    }

                    OHTestApp::EndSingleTimeCommands(cmd);

                    // 清理资源
                    indirectBuf.Destroy();
                    vkDestroyPipeline(device, compPipeline, nullptr);
                }
                vkDestroyPipelineLayout(device, compPipelineLayout, nullptr);
            }
            if (compShader != VK_NULL_HANDLE) {
                vkDestroyShaderModule(device, compShader, nullptr);
                if (!logged_vkDestroyShaderModule) { 
                    GOLOGW("vkDestroyShaderModule completed successfully"); 
                    logged_vkDestroyShaderModule = true; 
                }
            } else {
                GOLOGE("Shader module is null; skip vkDestroyShaderModule");
            }
        } else {
            GOLOGE("Compute shader creation failed; skip compute pipeline tests");
        }
    }

    {
        // vkCmdFillBuffer 测试
        OHTestApp::Buffer fillBuf;
        OHTestApp::Buffer::BufferDescriptor fbDesc{ "SmokeFillBuf", 256u, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT };
        if (fillBuf.Init(fbDesc)) {
            VkCommandBuffer cmd = OHTestApp::BeginSingleTimeCommands();
            vkCmdFillBuffer(cmd, fillBuf.GetNativeBuffer(), 0, 256, 0x12345678);
            OHTestApp::EndSingleTimeCommands(cmd);
            if (!logged_vkCmdFillBuffer) { GOLOGW("vkCmdFillBuffer completed successfully"); logged_vkCmdFillBuffer = true; }
            fillBuf.Destroy();
        }

        // vkCmdPushConstants 测试（需要有管线布局支持 push constants）
        {
            VkPushConstantRange pushRange{};
            pushRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
            pushRange.offset = 0;
            pushRange.size = 128;

            VkPipelineLayoutCreateInfo pushLayoutInfo{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
            pushLayoutInfo.pushConstantRangeCount = 1;
            pushLayoutInfo.pPushConstantRanges = &pushRange;

            VkPipelineLayout pushLayout = VK_NULL_HANDLE;
            VkResult plr = vkCreatePipelineLayout(device, &pushLayoutInfo, nullptr, &pushLayout);
            if (plr == VK_SUCCESS) {
                VkCommandBuffer cmd = OHTestApp::BeginSingleTimeCommands();
                uint32_t pushData[32] = {0};
                for (int i = 0; i < 32; ++i) pushData[i] = i;
                vkCmdPushConstants(cmd, pushLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, 128, pushData);
                OHTestApp::EndSingleTimeCommands(cmd);
                if (!logged_vkCmdPushConstants) { GOLOGW("vkCmdPushConstants completed successfully"); logged_vkCmdPushConstants = true; }
                vkDestroyPipelineLayout(device, pushLayout, nullptr);
            } else {
                GOLOGE("vkCreatePipelineLayout for push constants failed: %d", plr);
            }
        }

        // vkCmdResetEvent 测试
        VkEvent evt = VK_NULL_HANDLE;
        VkEventCreateInfo evtInfo{ VK_STRUCTURE_TYPE_EVENT_CREATE_INFO };
        VkResult evtResult = vkCreateEvent(device, &evtInfo, nullptr, &evt);
        if (evtResult == VK_SUCCESS) {
            VkCommandBuffer cmd = OHTestApp::BeginSingleTimeCommands();
            vkCmdResetEvent(cmd, evt, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
            OHTestApp::EndSingleTimeCommands(cmd);
            if (!logged_vkCmdResetEvent) { GOLOGW("vkCmdResetEvent completed successfully"); logged_vkCmdResetEvent = true; }
            vkDestroyEvent(device, evt, nullptr);
        } else {
            GOLOGE("vkCreateEvent failed: %d", evtResult);
        }

        // vkCmdEndQuery 测试
        VkQueryPool qp3 = VK_NULL_HANDLE;
        VkQueryPoolCreateInfo qci3{ VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO };
        qci3.queryType = VK_QUERY_TYPE_OCCLUSION;
        qci3.queryCount = 1;
        VkResult qr3 = vkCreateQueryPool(device, &qci3, nullptr, &qp3);
        if (qr3 == VK_SUCCESS) {
            VkCommandBuffer cmd = OHTestApp::BeginSingleTimeCommands();
            vkCmdResetQueryPool(cmd, qp3, 0, 1);
            vkCmdBeginQuery(cmd, qp3, 0, 0);
            vkCmdEndQuery(cmd, qp3, 0);
            OHTestApp::EndSingleTimeCommands(cmd);
            if (!logged_vkCmdEndQuery) { GOLOGW("vkCmdEndQuery completed successfully"); logged_vkCmdEndQuery = true; }
            vkDestroyQueryPool(device, qp3, nullptr);
        } else {
            GOLOGE("vkCreateQueryPool for vkCmdEndQuery test failed: %d", qr3);
        }

        // vkCmdNextSubpass 测试
        {
            VkAttachmentDescription multiAttach{};
            multiAttach.format = m_swapChainImageFormat;
            multiAttach.samples = VK_SAMPLE_COUNT_1_BIT;
            multiAttach.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
            multiAttach.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
            multiAttach.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
            multiAttach.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

            VkAttachmentReference colorRef{ 0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };

            VkSubpassDescription subpasses[2] = {};
            subpasses[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
            subpasses[0].colorAttachmentCount = 1;
            subpasses[0].pColorAttachments = &colorRef;
            subpasses[1].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
            subpasses[1].colorAttachmentCount = 1;
            subpasses[1].pColorAttachments = &colorRef;

            VkSubpassDependency dependency{};
            dependency.srcSubpass = 0;
            dependency.dstSubpass = 1;
            dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
            dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
            dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
            dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;

            VkRenderPassCreateInfo multiRpInfo{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
            multiRpInfo.attachmentCount = 1;
            multiRpInfo.pAttachments = &multiAttach;
            multiRpInfo.subpassCount = 2;
            multiRpInfo.pSubpasses = subpasses;
            multiRpInfo.dependencyCount = 1;
            multiRpInfo.pDependencies = &dependency;

            VkRenderPass multiRp = VK_NULL_HANDLE;
            VkResult mrr = vkCreateRenderPass(device, &multiRpInfo, nullptr, &multiRp);
            if (mrr == VK_SUCCESS) {
                const uint32_t testW = 32, testH = 32;
                OHTestApp::Image multiImg;
                multiImg.Init(OHTestApp::Image::ImageDescriptor()
                    .Name("SmokeMultiSubpass").Width(testW).Height(testH).Format(m_swapChainImageFormat)
                    .Tile(VK_IMAGE_TILING_OPTIMAL)
                    .MemProperties(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
                    .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT));
                VkImageView multiView = multiImg.GetNativeImageView();

                if (multiView != VK_NULL_HANDLE) {
                    VkFramebufferCreateInfo multiFbInfo{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
                    multiFbInfo.renderPass = multiRp;
                    multiFbInfo.attachmentCount = 1;
                    multiFbInfo.pAttachments = &multiView;
                    multiFbInfo.width = testW;
                    multiFbInfo.height = testH;
                    multiFbInfo.layers = 1;

                    VkFramebuffer multiFb = VK_NULL_HANDLE;
                    VkResult mfr = vkCreateFramebuffer(device, &multiFbInfo, nullptr, &multiFb);
                    if (mfr == VK_SUCCESS) {
                        VkCommandBuffer cmd = OHTestApp::BeginSingleTimeCommands();

                        OHTestApp::RecordImageLayoutTransitionCommands(
                            cmd, multiImg.GetNativeImage(), VK_IMAGE_ASPECT_COLOR_BIT,
                            VK_IMAGE_LAYOUT_UNDEFINED, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
                            VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);

                        VkClearValue clearVal;
                        clearVal.color = {{0.0f, 0.0f, 0.0f, 1.0f}};
                        VkRenderPassBeginInfo rpBegin{ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
                        rpBegin.renderPass = multiRp;
                        rpBegin.framebuffer = multiFb;
                        rpBegin.renderArea = {{0, 0}, {testW, testH}};
                        rpBegin.clearValueCount = 1;
                        rpBegin.pClearValues = &clearVal;

                        vkCmdBeginRenderPass(cmd, &rpBegin, VK_SUBPASS_CONTENTS_INLINE);
                        vkCmdNextSubpass(cmd, VK_SUBPASS_CONTENTS_INLINE);
                        vkCmdEndRenderPass(cmd);

                        OHTestApp::EndSingleTimeCommands(cmd);
                        if (!logged_vkCmdNextSubpass) { GOLOGW("vkCmdNextSubpass completed successfully"); logged_vkCmdNextSubpass = true; }

                        vkDestroyFramebuffer(device, multiFb, nullptr);
                    } else {
                        GOLOGE("vkCreateFramebuffer for multi-subpass test failed: %d", mfr);
                    }
                }
                multiImg.Destroy();
                vkDestroyRenderPass(device, multiRp, nullptr);
            } else {
                GOLOGE("vkCreateRenderPass for multi-subpass test failed: %d", mrr);
            }
        }

        // vkCmdExecuteCommands 测试
        {
            VkCommandPoolCreateInfo secPoolInfo{ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
            secPoolInfo.queueFamilyIndex = OHTestApp::Device::Instance().GetQueueFamilyIndex();
            secPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;

            VkCommandPool secPool = VK_NULL_HANDLE;
            VkResult spr = vkCreateCommandPool(device, &secPoolInfo, nullptr, &secPool);
            if (spr == VK_SUCCESS) {
                VkCommandBufferAllocateInfo secAllocInfo{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
                secAllocInfo.commandPool = secPool;
                secAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
                secAllocInfo.commandBufferCount = 1;

                VkCommandBuffer secCmd = VK_NULL_HANDLE;
                VkResult sar = vkAllocateCommandBuffers(device, &secAllocInfo, &secCmd);
                if (sar == VK_SUCCESS) {
                    VkAttachmentDescription secAttach{};
                    secAttach.format = m_swapChainImageFormat;
                    secAttach.samples = VK_SAMPLE_COUNT_1_BIT;
                    secAttach.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
                    secAttach.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
                    secAttach.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
                    secAttach.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

                    VkAttachmentReference secColorRef{ 0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
                    VkSubpassDescription secSubpass{};
                    secSubpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
                    secSubpass.colorAttachmentCount = 1;
                    secSubpass.pColorAttachments = &secColorRef;

                    VkRenderPassCreateInfo secRpInfo{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
                    secRpInfo.attachmentCount = 1;
                    secRpInfo.pAttachments = &secAttach;
                    secRpInfo.subpassCount = 1;
                    secRpInfo.pSubpasses = &secSubpass;

                    VkRenderPass secRp = VK_NULL_HANDLE;
                    VkResult srr = vkCreateRenderPass(device, &secRpInfo, nullptr, &secRp);
                    if (srr == VK_SUCCESS) {
                        VkCommandBufferInheritanceInfo inheritInfo{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO };
                        inheritInfo.renderPass = secRp;
                        inheritInfo.subpass = 0;

                        VkCommandBufferBeginInfo secBeginInfo{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
                        secBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
                        secBeginInfo.pInheritanceInfo = &inheritInfo;

                        VkResult sbr = vkBeginCommandBuffer(secCmd, &secBeginInfo);
                        if (sbr == VK_SUCCESS) {
                            vkEndCommandBuffer(secCmd);

                            VkCommandBuffer primaryCmd = OHTestApp::BeginSingleTimeCommands();
                            vkCmdExecuteCommands(primaryCmd, 1, &secCmd);
                            OHTestApp::EndSingleTimeCommands(primaryCmd);

                            if (!logged_vkCmdExecuteCommands) { GOLOGW("vkCmdExecuteCommands completed successfully"); logged_vkCmdExecuteCommands = true; }
                        } else {
                            GOLOGE("vkBeginCommandBuffer for secondary buffer failed: %d", sbr);
                        }
                        vkDestroyRenderPass(device, secRp, nullptr);
                    } else {
                        GOLOGE("vkCreateRenderPass for secondary buffer test failed: %d", srr);
                    }
                } else {
                    GOLOGE("vkAllocateCommandBuffers for secondary buffer failed: %d", sar);
                }
                vkDestroyCommandPool(device, secPool, nullptr);
            } else {
                GOLOGE("vkCreateCommandPool for secondary buffer failed: %d", spr);
            }
        }
    }

    // 清理：描述符集布局
    if (dsl) { vkDestroyDescriptorSetLayout(device, dsl, nullptr); }
}

void HelloVK::Reset(OHNativeWindow *newWindow, NativeResourceManager *newManager)
{
    m_window.reset(newWindow);
    m_assetManager = newManager;
    OHTestApp::AAssetImporter::Instance().Init(newManager);

    if (m_initialized) {
        CreateSurface();
        RecreateSwapChain();
    }
}

void HelloVK::RecreateSwapChain()
{
    VkResult result = vkDeviceWaitIdle(m_device);
    if (result == VK_SUCCESS) {
        GOLOGW("vkDeviceWaitIdle completed successfully");
    } else {
        GOLOGE("vkDeviceWaitIdle failed with error: %d", result);
    }
    CleanupSwapChain();
    CreateSwapChain();
    CreateImageViews();
    FGCreateDepthResources();
    FGCreateSwapchainSyncObjects();

    FGDestroyColorResources();
    FGCreateColorResources();
    FGDestroyUIRenderer();
    FGDestroyMainSceneRenderer();
    FGInitUIRenderer();
    FGInitMainSceneRenderer();
}

void HelloVK::Render()
{
    
    FGBalancedInterRender();
}

void HelloVK::OnOrientationChange()
{
    RecreateSwapChain();
    m_orientationChanged = false;
}

void HelloVK::CleanupSwapChain()
{
    m_sceneDepthStencil.Destroy();

    for (auto const &info : m_swapchainInfo) {
        if (info.renderEnd != VK_NULL_HANDLE) {
            GOLOGD("Destroying renderEnd semaphore");
            vkDestroySemaphore(m_device, info.renderEnd, nullptr);
            GOLOGW("vkDestroySemaphore completed successfully");
        }
    }

    m_swapchainInfo.clear();

    if (m_sceneFramebuffer != VK_NULL_HANDLE) {
        GOLOGD("Destroying framebuffer");
        vkDestroyFramebuffer(m_device, m_sceneFramebuffer, nullptr);
        GOLOGW("vkDestroyFramebuffer completed successfully");
        m_sceneFramebuffer = VK_NULL_HANDLE;
    }

    for (size_t i = 0; i < m_swapChainImageViews.size(); i++) {
        GOLOGD("Destroying image view %zu", i);
        vkDestroyImageView(m_device, m_swapChainImageViews[i], nullptr);
        GOLOGW("vkDestroyImageView completed successfully");
    }

    GOLOGD("Destroying swapchain");
    vkDestroySwapchainKHR(m_device, m_swapChain, nullptr);
    GOLOGW("vkDestroySwapchainKHR completed successfully");
}

void HelloVK::Cleanup()
{
    VkResult result = vkDeviceWaitIdle(m_device);
    if (result == VK_SUCCESS) {
        GOLOGW("vkDeviceWaitIdle completed successfully");
    } else {
        GOLOGE("vkDeviceWaitIdle failed with error: %d", result);
    }
    CleanupSwapChain();

    for (auto &info : m_framesInFlights) {
        if (info.commandPool != VK_NULL_HANDLE) {
            GOLOGD("Destroying command pool");
            vkDestroyCommandPool(m_device, info.commandPool, nullptr);
            GOLOGW("vkDestroyCommandPool completed successfully");
        }

        if (info.fence != VK_NULL_HANDLE) {
            GOLOGD("Destroying fence");
            vkDestroyFence(m_device, info.fence, nullptr);
            GOLOGW("vkDestroyFence completed successfully");
        }

        if (info.acquire != VK_NULL_HANDLE) {
            GOLOGD("Destroying acquire semaphore");
            vkDestroySemaphore(m_device, info.acquire, nullptr);
            GOLOGW("vkDestroySemaphore completed successfully");
        }
    }

    m_framesInFlights.clear();

    GOLOGD("Destroying device");
    vkDestroyDevice(m_device, nullptr);
    GOLOGW("vkDestroyDevice completed successfully");

    if (ENABLE_VALIDATION_LAYERS) {
//        DestroyDebugUtilsMessengerEXT(m_instance, m_debugMessenger, nullptr);
    }

    GOLOGD("Destroying surface");
    vkDestroySurfaceKHR(m_instance, m_surface, nullptr);
    GOLOGW("vkDestroySurfaceKHR completed successfully");
    
    GOLOGD("Destroying instance");
    vkDestroyInstance(m_instance, nullptr);
    GOLOGW("vkDestroyInstance completed successfully");
    m_initialized = false;
}

void HelloVK::SetupDebugMessenger()
{
    if (!ENABLE_VALIDATION_LAYERS) {
        return;
    }

}

bool HelloVK::CheckValidationLayerSupport()
{
    uint32_t layerCount;
    VkResult result = vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
    if (result == VK_SUCCESS) {
        GOLOGW("vkEnumerateInstanceLayerProperties (count) completed successfully");
    } else {
        GOLOGE("vkEnumerateInstanceLayerProperties (count) failed with error: %d", result);
        return false;
    }

    std::vector<VkLayerProperties> availableLayers(layerCount);
    result = vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
    if (result == VK_SUCCESS) {
        GOLOGW("vkEnumerateInstanceLayerProperties (data) completed successfully");
    } else {
        GOLOGE("vkEnumerateInstanceLayerProperties (data) failed with error: %d", result);
        return false;
    }

    for (const char *layerName : m_validationLayers) {
        bool layerFound = false;
        for (const auto &layerProperties : availableLayers) {
            GOLOGI("Avalible %s", layerProperties.layerName);
            if (strcmp(layerName, layerProperties.layerName) == 0) {
                layerFound = true;
                break;
            }
        }

        if (!layerFound) {
            return false;
        }
    }

    return true;
}

std::vector<const char *> HelloVK::GetRequiredExtensions(bool enableValidationLayers)
{
    std::vector<const char *> extensions = { VK_KHR_SURFACE_EXTENSION_NAME, VK_OHOS_SURFACE_EXTENSION_NAME };

    if (enableValidationLayers) {
        extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
    }

    return extensions;
}

void HelloVK::CreateInstance()
{
    // validation layers requested, but not available!
    if (ENABLE_VALIDATION_LAYERS && !CheckValidationLayerSupport()) {
        GOLOGE("Validation layers are unavailable");
        return;
    }
    auto requiredExtensions = GetRequiredExtensions(ENABLE_VALIDATION_LAYERS);

    VkApplicationInfo appInfo{};
    appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
    appInfo.pApplicationName = "Hello Triangle";
    appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
    appInfo.pEngineName = "No Engine";
    appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
    appInfo.apiVersion = VK_API_VERSION_1_3;

    VkInstanceCreateInfo createInfo{};
    createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
    createInfo.pApplicationInfo = &appInfo;
    createInfo.enabledExtensionCount = (uint32_t)requiredExtensions.size();
    createInfo.ppEnabledExtensionNames = requiredExtensions.data();
    createInfo.pApplicationInfo = &appInfo;

    if (ENABLE_VALIDATION_LAYERS) {
//        VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
//        createInfo.enabledLayerCount = static_cast<uint32_t>(m_validationLayers.size());
//        createInfo.ppEnabledLayerNames = m_validationLayers.data();
//        PopulateDebugMessengerCreateInfo(debugCreateInfo);
//        createInfo.pNext = &debugCreateInfo;
    }

    VkResult result = vkCreateInstance(&createInfo, nullptr, &m_instance);
    if (result == VK_SUCCESS) {
        GOLOGW("vkCreateInstance completed successfully");
    } else {
        GOLOGE("vkCreateInstance failed with error: %d", result);
        return;
    }

    if (ENABLE_VALIDATION_LAYERS) {
//        OHTestApp::SetupDebugLabels(m_instance);
    }

    uint32_t extensionCount = 0;
    result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
    if (result == VK_SUCCESS) {
        GOLOGW("vkEnumerateInstanceExtensionProperties (count) completed successfully");
    } else {
        GOLOGE("vkEnumerateInstanceExtensionProperties (count) failed with error: %d", result);
    }
    
    std::vector<VkExtensionProperties> extensions(extensionCount);
    result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
    if (result == VK_SUCCESS) {
        GOLOGW("vkEnumerateInstanceExtensionProperties (data) completed successfully");
    } else {
        GOLOGE("vkEnumerateInstanceExtensionProperties (data) failed with error: %d", result);
    }
}

/*
 * CreateSurface can only be called after the ohos ecosystem has had the
 * chance to provide a native window. This happens after the APP_CMD_START event
 * has had a chance to be called.
 *
 * Notice the window.get() call which is only valid after window has been set to
 * a non null value
 */
void HelloVK::CreateSurface()
{
    if (!m_window) {
        GOLOGE("window not initialized");
        return;
    }

    const VkSurfaceCreateInfoOHOS create_info {
        .sType = VK_STRUCTURE_TYPE_SURFACE_CREATE_INFO_OHOS,
        .pNext = nullptr,
        .flags = 0,
        .window = m_window.get()
    };

    VkResult result = vkCreateSurfaceOHOS(m_instance, &create_info, nullptr, &m_surface);
    if (result == VK_SUCCESS) {
        GOLOGW("vkCreateSurfaceOHOS completed successfully");
    } else {
        GOLOGE("vkCreateSurfaceOHOS failed with error: %d", result);
    }
}

// BEGIN DEVICE SUITABILITY
// Functions to find a suitable physical device to execute Vulkan commands.

QueueFamilyIndices HelloVK::FindQueueFamilies(VkPhysicalDevice device)
{
    QueueFamilyIndices indices;

    uint32_t queueFamilyCount = 0;
    vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
    GOLOGW("vkGetPhysicalDeviceQueueFamilyProperties (count) completed successfully");

    std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
    vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
    GOLOGW("vkGetPhysicalDeviceQueueFamilyProperties (data) completed successfully");

    int i = 0;
    for (const auto &queueFamily : queueFamilies) {
        if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
            indices.graphicsFamily = i;
        }

        VkBool32 presentSupport = false;
        VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(device, i, m_surface, &presentSupport);
        if (result == VK_SUCCESS) {
            GOLOGW("vkGetPhysicalDeviceSurfaceSupportKHR completed successfully");
        } else {
            GOLOGE("vkGetPhysicalDeviceSurfaceSupportKHR failed with error: %d", result);
        }
        
        if (presentSupport) {
            indices.presentFamily = i;
        }

        if (indices.isComplete()) {
            break;
        }

        ++i;
    }
    return indices;
}

bool HelloVK::CheckDeviceExtensionSupport(VkPhysicalDevice device)
{
    uint32_t extensionCount;
    VkResult result = vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
    if (result == VK_SUCCESS) {
        GOLOGW("vkEnumerateDeviceExtensionProperties (count) completed successfully");
    } else {
        GOLOGE("vkEnumerateDeviceExtensionProperties (count) failed with error: %d", result);
        return false;
    }

    std::vector<VkExtensionProperties> availableExtensions(extensionCount);
    result = vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
    if (result == VK_SUCCESS) {
        GOLOGW("vkEnumerateDeviceExtensionProperties (data) completed successfully");
    } else {
        GOLOGE("vkEnumerateDeviceExtensionProperties (data) failed with error: %d", result);
        return false;
    }

    std::set<std::string> requiredExtensions(m_deviceExtensions.begin(), m_deviceExtensions.end());

    for (const auto &extension : availableExtensions) {
        requiredExtensions.erase(extension.extensionName);
    }

    if (ENABLE_VALIDATION_LAYERS) {
        // Workaround: Probably OHOS Vulkan bug...
//        if (requiredExtensions.size() == 1U && *requiredExtensions.cbegin() == VK_KHR_SWAPCHAIN_EXTENSION_NAME) {
//            return true;
//        }
    }

    return requiredExtensions.empty();
}

SwapChainSupportDetails HelloVK::QuerySwapChainSupport(VkPhysicalDevice device)
{
    SwapChainSupportDetails details;

    VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, m_surface, &details.capabilities);
    if (result == VK_SUCCESS) {
        GOLOGW("vkGetPhysicalDeviceSurfaceCapabilitiesKHR completed successfully");
    } else {
        GOLOGE("vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed with error: %d", result);
    }

    uint32_t formatCount;
    result = vkGetPhysicalDeviceSurfaceFormatsKHR(device, m_surface, &formatCount, nullptr);
    if (result == VK_SUCCESS) {
        GOLOGW("vkGetPhysicalDeviceSurfaceFormatsKHR (count) completed successfully");
    } else {
        GOLOGE("vkGetPhysicalDeviceSurfaceFormatsKHR (count) failed with error: %d", result);
    }

    if (formatCount != 0) {
        details.formats.resize(formatCount);
        result = vkGetPhysicalDeviceSurfaceFormatsKHR(device, m_surface, &formatCount, details.formats.data());
        if (result == VK_SUCCESS) {
            GOLOGW("vkGetPhysicalDeviceSurfaceFormatsKHR (data) completed successfully");
        } else {
            GOLOGE("vkGetPhysicalDeviceSurfaceFormatsKHR (data) failed with error: %d", result);
        }
    }

    uint32_t presentModeCount;
    result = vkGetPhysicalDeviceSurfacePresentModesKHR(device, m_surface, &presentModeCount, nullptr);
    if (result == VK_SUCCESS) {
        GOLOGW("vkGetPhysicalDeviceSurfacePresentModesKHR (count) completed successfully");
    } else {
        GOLOGE("vkGetPhysicalDeviceSurfacePresentModesKHR (count) failed with error: %d", result);
    }

    if (presentModeCount != 0) {
        details.presentModes.resize(presentModeCount);
        result = vkGetPhysicalDeviceSurfacePresentModesKHR(device, m_surface, &presentModeCount, details.presentModes.data());
        if (result == VK_SUCCESS) {
            GOLOGW("vkGetPhysicalDeviceSurfacePresentModesKHR (data) completed successfully");
        } else {
            GOLOGE("vkGetPhysicalDeviceSurfacePresentModesKHR (data) failed with error: %d", result);
        }
    }
    return details;
}

bool HelloVK::IsDeviceSuitable(VkPhysicalDevice device)
{
    QueueFamilyIndices indices = FindQueueFamilies(device);
    bool extensionsSupported = CheckDeviceExtensionSupport(device);
    bool swapChainAdequate = false;
    if (extensionsSupported) {
        SwapChainSupportDetails swapChainSupport = QuerySwapChainSupport(device);
        swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
    }

    return indices.isComplete() && extensionsSupported && swapChainAdequate;
}

void HelloVK::PickPhysicalDevice()
{
    uint32_t deviceCount = 0;
    VkResult result = vkEnumeratePhysicalDevices(m_instance, &deviceCount, nullptr);
    if (result == VK_SUCCESS) {
        GOLOGW("vkEnumeratePhysicalDevices (count) completed successfully");
    } else {
        GOLOGE("vkEnumeratePhysicalDevices (count) failed with error: %d", result);
        return;
    }

    if (deviceCount <= 0) {
        GOLOGE("failed to find GPUs with Vulkan support!");
        return;
    }

    std::vector<VkPhysicalDevice> devices(deviceCount);
    result = vkEnumeratePhysicalDevices(m_instance, &deviceCount, devices.data());
    if (result == VK_SUCCESS) {
        GOLOGW("vkEnumeratePhysicalDevices (data) completed successfully");
    } else {
        GOLOGE("vkEnumeratePhysicalDevices (data) failed with error: %d", result);
        return;
    }

    for (const auto &device : devices) {
        if (IsDeviceSuitable(device)) {
            m_physicalDevice = device;
            break;
        }
    }

    if (m_physicalDevice == VK_NULL_HANDLE) {
        GOLOGE("failed to find a suitable GPU!");
        return;
    }

    vkGetPhysicalDeviceFeatures(m_physicalDevice, &m_physicalDeviceFeatures);
    GOLOGW("vkGetPhysicalDeviceFeatures completed successfully");
    
    vkGetPhysicalDeviceProperties(m_physicalDevice, &m_physicalDeviceProperties);
    GOLOGW("vkGetPhysicalDeviceProperties completed successfully");
}
// END DEVICE SUITABILITY

void HelloVK::CreateLogicalDeviceAndQueue()
{
    QueueFamilyIndices indices = FindQueueFamilies(m_physicalDevice);
    std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
    std::set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value() };
    float queuePriority = 1.0F;
    for (uint32_t queueFamily : uniqueQueueFamilies) {
        VkDeviceQueueCreateInfo queueCreateInfo{};
        queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
        queueCreateInfo.queueFamilyIndex = queueFamily;
        queueCreateInfo.queueCount = 1;
        queueCreateInfo.pQueuePriorities = &queuePriority;
        queueCreateInfos.push_back(queueCreateInfo);
    }

    // === 详细诊断：检查动态渲染扩展可用性 ===
    std::vector<const char*> deviceExtensions(m_deviceExtensions.begin(), m_deviceExtensions.end());
    uint32_t extCount = 0;
    vkEnumerateDeviceExtensionProperties(m_physicalDevice, nullptr, &extCount, nullptr);
    std::vector<VkExtensionProperties> availableExts(extCount);
    vkEnumerateDeviceExtensionProperties(m_physicalDevice, nullptr, &extCount, availableExts.data());
    
    GOLOGI("=== Device Extension Diagnostic ===");
    GOLOGI("Total available device extensions: %u", extCount);
    
    // 列出所有可用扩展（仅记录与渲染相关的）
    for (const auto& ext : availableExts) {
        if (strstr(ext.extensionName, "render") || strstr(ext.extensionName, "dynamic")) {
            GOLOGI("  - %s (spec version: %u)", ext.extensionName, ext.specVersion);
        }
    }
    
    bool hasDynamicRendering = false;
    for (const auto& ext : availableExts) {
        if (strcmp(ext.extensionName, VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME) == 0) {
            hasDynamicRendering = true;
            GOLOGI("Found VK_KHR_dynamic_rendering (spec version: %u), enabling it", ext.specVersion);
            deviceExtensions.push_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
            break;
        }
    }
    
    if (!hasDynamicRendering) {
        GOLOGE("VK_KHR_dynamic_rendering NOT available on this device");
        GOLOGE("   Device Vulkan API version: %u.%u.%u", 
            VK_VERSION_MAJOR(m_physicalDeviceProperties.apiVersion),
            VK_VERSION_MINOR(m_physicalDeviceProperties.apiVersion),
            VK_VERSION_PATCH(m_physicalDeviceProperties.apiVersion));
        GOLOGE("   Device name: %s", m_physicalDeviceProperties.deviceName);
    }
    
    GOLOGI("=================================");

    VkDeviceCreateInfo createInfo{};
    VkPhysicalDeviceFeatures deviceFeatures{};
    VkPhysicalDeviceFloat16Int8FeaturesKHR float16Int8Features{};
    float16Int8Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR;
    float16Int8Features.pNext = nullptr;
    float16Int8Features.shaderFloat16 = VK_TRUE;
    float16Int8Features.shaderInt8 = VK_FALSE;

    // 启用动态渲染特性（Vulkan 1.3 或 KHR 扩展）
    VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamicRenderingFeature{};
    dynamicRenderingFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR;
    dynamicRenderingFeature.pNext = &float16Int8Features;
    dynamicRenderingFeature.dynamicRendering = VK_TRUE;

    VkPhysicalDeviceVulkan13Features vk13Features{};
    vk13Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
    vk13Features.pNext = &dynamicRenderingFeature; // 链接动态渲染特性
    vk13Features.dynamicRendering = VK_TRUE;

    deviceFeatures.samplerAnisotropy = m_physicalDeviceFeatures.samplerAnisotropy;
    deviceFeatures.shaderInt16 = VK_TRUE;
    deviceFeatures.fragmentStoresAndAtomics = VK_TRUE;

    createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
    createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
    createInfo.pQueueCreateInfos = queueCreateInfos.data();
    createInfo.pEnabledFeatures = &deviceFeatures;
    createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
    createInfo.ppEnabledExtensionNames = deviceExtensions.data();
    createInfo.pNext = &vk13Features; // 链接特性结构体

    VkResult result = vkCreateDevice(m_physicalDevice, &createInfo, nullptr, &m_device);
    if (result == VK_SUCCESS) {
        GOLOGW("vkCreateDevice completed successfully");
    } else {
        GOLOGE("vkCreateDevice failed with error: %d", result);
        return;
    }

    vkGetDeviceQueue(m_device, indices.graphicsFamily.value(), 0, &m_graphicsQueue);
    GOLOGW("vkGetDeviceQueue (graphics) completed successfully");
    
    vkGetDeviceQueue(m_device, indices.presentFamily.value(), 0, &m_presentQueue);
    GOLOGW("vkGetDeviceQueue (present) completed successfully");
}

void HelloVK::EstablishDisplaySizeIdentity()
{
    VkSurfaceCapabilitiesKHR capabilities;
    VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_physicalDevice, m_surface, &capabilities);
    if (result == VK_SUCCESS) {
        GOLOGW("vkGetPhysicalDeviceSurfaceCapabilitiesKHR completed successfully");
    } else {
        GOLOGE("vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed with error: %d", result);
        return;
    }

    float ratio;
    if (capabilities.currentExtent.width < capabilities.currentExtent.height) {
        ratio = static_cast<float>(capabilities.currentExtent.width) / m_resolution;
    } else {
        ratio = static_cast<float>(capabilities.currentExtent.height) / m_resolution;
    }
    capabilities.currentExtent.width = static_cast<uint32_t>(capabilities.currentExtent.width / ratio);
    capabilities.currentExtent.height = static_cast<uint32_t>(capabilities.currentExtent.height / ratio);

    m_displaySizeIdentity = capabilities.currentExtent;
}

void HelloVK::ExecuteCreateSwapChain(VkSwapchainCreateInfoKHR &createInfo, uint32_t imageCount, VkFormat format)
{
    VkResult result = vkCreateSwapchainKHR(m_device, &createInfo, nullptr, &m_swapChain);
    if (result == VK_SUCCESS) {
        GOLOGW("vkCreateSwapchainKHR completed successfully");
    } else {
        GOLOGE("vkCreateSwapchainKHR failed with error: %d", result);
        return;
    }
    
    result = vkGetSwapchainImagesKHR(m_device, m_swapChain, &imageCount, nullptr);
    if (result == VK_SUCCESS) {
        GOLOGW("vkGetSwapchainImagesKHR (count) completed successfully");
    } else {
        GOLOGE("vkGetSwapchainImagesKHR (count) failed with error: %d", result);
    }
    
    m_swapChainImages.resize(imageCount);
    result = vkGetSwapchainImagesKHR(m_device, m_swapChain, &imageCount, m_swapChainImages.data());
    if (result == VK_SUCCESS) {
        GOLOGW("vkGetSwapchainImagesKHR (data) completed successfully");
    } else {
        GOLOGE("vkGetSwapchainImagesKHR (data) failed with error: %d", result);
    }

    for (uint32_t i = 0U; i < imageCount; ++i) {
        char label[256U];
        
        // 使用安全的 snprintf 替换 snprintf_s
        int iRet = std::snprintf(label, sizeof(label), "Swapchain image #%u", i);
        if (iRet < 0 || static_cast<size_t>(iRet) >= sizeof(label)) {
            // 格式化失败或缓冲区不足，使用默认标签
            std::strncpy(label, "Swapchain image", sizeof(label) - 1);
            label[sizeof(label) - 1] = '\0';  // 确保以null结尾
            GOLOGE("snprintf failed or buffer too small for swapchain image #%u", i);
        }
        
        OHTestApp::SetLabel(m_device, m_swapChainImages[i], VK_OBJECT_TYPE_IMAGE, label);
    }

    m_swapChainImageFormat = format;
    m_swapChainExtent = m_displaySizeIdentity;
    GOLOGI("create swapchain image count: %u", imageCount);
}

void HelloVK::CreateSwapChain()
{
    SwapChainSupportDetails swapChainSupport = QuerySwapChainSupport(m_physicalDevice);

    auto chooseSwapSurfaceFormat = [](const std::vector<VkSurfaceFormatKHR> &availableFormats) {
        for (const auto &availableFormat : availableFormats) {
            if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB &&
                availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
                return availableFormat;
            }
        }

        return availableFormats[0];
    };

    VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);

    VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;

    uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
    if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
        imageCount = swapChainSupport.capabilities.maxImageCount;
    }
    GOLOGI("minSwapchain image count: %u request: %u", swapChainSupport.capabilities.minImageCount, imageCount);
    m_pretransformFlag = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;

    VkSwapchainCreateInfoKHR createInfo{};
    createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
    createInfo.surface = m_surface;
    createInfo.minImageCount = imageCount;
    createInfo.imageFormat = surfaceFormat.format;
    createInfo.imageColorSpace = surfaceFormat.colorSpace;
    createInfo.imageExtent = m_displaySizeIdentity;
    createInfo.imageArrayLayers = 1;

    createInfo.imageUsage =
        VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;

    createInfo.preTransform = m_pretransformFlag;

    QueueFamilyIndices indices = FindQueueFamilies(m_physicalDevice);
    uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(), indices.presentFamily.value()};

    if (indices.graphicsFamily != indices.presentFamily) {
        createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
        createInfo.queueFamilyIndexCount = 2U;
        createInfo.pQueueFamilyIndices = queueFamilyIndices;
    } else {
        createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
        createInfo.queueFamilyIndexCount = 0U;
        createInfo.pQueueFamilyIndices = nullptr;
    }

    createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
    createInfo.presentMode = presentMode;
    createInfo.clipped = VK_TRUE;
    createInfo.oldSwapchain = VK_NULL_HANDLE;

    ExecuteCreateSwapChain(createInfo, imageCount, surfaceFormat.format);
}

void HelloVK::CreateImageViews()
{
    m_swapChainImageViews.resize(m_swapChainImages.size());
    for (size_t i = 0; i < m_swapChainImages.size(); ++i) {
        VkImageViewCreateInfo createInfo{};
        createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
        createInfo.image = m_swapChainImages[i];
        createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
        createInfo.format = m_swapChainImageFormat;
        createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
        createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
        createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
        createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
        createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
        createInfo.subresourceRange.baseMipLevel = 0;
        createInfo.subresourceRange.levelCount = 1;
        createInfo.subresourceRange.baseArrayLayer = 0;
        createInfo.subresourceRange.layerCount = 1;
        
        VkResult result = vkCreateImageView(m_device, &createInfo, nullptr, &m_swapChainImageViews[i]);
        if (result == VK_SUCCESS) {
            GOLOGW("vkCreateImageView completed successfully for image %zu", i);
        } else {
            GOLOGE("vkCreateImageView failed with error: %d for image %zu", result, i);
        }
    }
}

void HelloVK::Acquire(VkSemaphore acquire)
{
    VkResult const result = vkAcquireNextImageKHR(m_device, m_swapChain, std::numeric_limits<uint64_t>::max(), acquire,
        VK_NULL_HANDLE, &m_imageIndex);
    if (result == VK_SUCCESS) {
        if (!s_loggedAcquireNextImage) {
            GOLOGW("vkAcquireNextImageKHR completed successfully");
            s_loggedAcquireNextImage = true;
        }
        return;
    }

    if (result != VK_ERROR_OUT_OF_DATE_KHR) {
        GOLOGE("Unexpected acquire result: %d", result);
        return;
    }

    RecreateSwapChain();

    VkResult retryResult = vkAcquireNextImageKHR(m_device, m_swapChain, std::numeric_limits<uint64_t>::max(), acquire, VK_NULL_HANDLE,
        &m_imageIndex);
    if (retryResult == VK_SUCCESS) {
        GOLOGW("vkAcquireNextImageKHR (retry) completed successfully");
    } else {
        GOLOGE("vkAcquireNextImageKHR (retry) failed with error: %d", retryResult);
    }
}

void HelloVK::Present(VkPresentInfoKHR const &presentInfo)
{
    VkResult const result = vkQueuePresentKHR(m_presentQueue, &presentInfo);
    if (result == VK_SUCCESS) {
        if (!s_loggedQueuePresent) {
            GOLOGW("vkQueuePresentKHR completed successfully");
            s_loggedQueuePresent = true;
        }
        return;
    }

    if (result == VK_SUBOPTIMAL_KHR) {
        GOLOGW("vkQueuePresentKHR returned VK_SUBOPTIMAL_KHR");
        m_orientationChanged = true;
        return;
    }

    if (result == VK_ERROR_OUT_OF_DATE_KHR) {
        GOLOGW("vkQueuePresentKHR returned VK_ERROR_OUT_OF_DATE_KHR");
        RecreateSwapChain();
        return;
    }

    GOLOGE("Unexpected present result: %d", result);
}

void HelloVK::FGInitDevice()
{
    // 使用真实的图形队列族索引与已获取的图形队列初始化全局 Device 单例
    QueueFamilyIndices indices = FindQueueFamilies(m_physicalDevice);
    uint32_t graphicsQueueFamilyIndex = indices.graphicsFamily.value();

    OHTestApp::Device::Instance().Init(OHTestApp::Device::DeviceDescriptor()
        .Name("Device")
        .Instance(m_instance)
        .PhysicalDevice(m_physicalDevice)
        .LogicalDevice(m_device)
        .QueueFamilyIndex(graphicsQueueFamilyIndex)
        .Queue(m_graphicsQueue));

    // 注意：此处不能使用一次性命令缓冲，也不能访问 m_sceneColor，
    // 因为命令池与场景图像尚未创建。任何需要的 barrier/布局过渡应放到
    // FGCreateColorResources 之后，或在真正使用的渲染路径中执行。
}

void HelloVK::FGCreateColorResources()
{
    m_sceneColor.Init(OHTestApp::Image::ImageDescriptor()
        .Name("Scene Color")
        .Width(m_swapChainExtent.width)
        .Height(m_swapChainExtent.height)
        .Format(m_swapChainImageFormat)
        .Tile(VK_IMAGE_TILING_OPTIMAL)
        .MemProperties(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
        .InitialLayout(VK_IMAGE_LAYOUT_UNDEFINED)
        .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT));

    m_sceneColor.GetNativeImageView();

    m_predictedColor.Init(OHTestApp::Image::ImageDescriptor()
        .Name("Predicted Color")
        .Width(m_swapChainExtent.width)
        .Height(m_swapChainExtent.height)
        .Format(m_swapChainImageFormat)
        .Tile(VK_IMAGE_TILING_OPTIMAL)
        .MemProperties(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
        .InitialLayout(VK_IMAGE_LAYOUT_UNDEFINED)
        .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT));

    m_predictedColor.GetNativeImageView();
}

void HelloVK::FGDestroyColorResources()
{
    m_sceneColor.Destroy();
    m_predictedColor.Destroy();
}

void HelloVK::FGCreateDepthResources()
{
    VkFormat const format = OHTestApp::Device::Instance().FindDepthFormat();

    m_sceneDepthStencil.Init(OHTestApp::Image::ImageDescriptor()
        .Name("Scene Depth/Stencil")
        .Width(m_swapChainExtent.width)
        .Height(m_swapChainExtent.height)
        .Format(format)
        .Tile(VK_IMAGE_TILING_OPTIMAL)
        .MemProperties(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
        .InitialLayout(VK_IMAGE_LAYOUT_UNDEFINED)
        .Usage(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT));

    m_sceneDepthStencil.GetNativeImageView(format, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
}

void HelloVK::CreateCommandPoolResources(const VkSemaphoreCreateInfo &semaphoreInfo,
    VkCommandPoolCreateInfo const &poolInfo, const VkFenceCreateInfo &fenceInfo,
    VkCommandBufferAllocateInfo &commandBufferAllocateInfo)
{
    for (uint32_t i = 0U; i < OHTestApp::FRAMES_IN_FLIGHT; ++i) {
        FrameInFlight &fif = m_framesInFlights[static_cast<size_t>(i)];
        
        VkResult result = vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &fif.acquire);
        if (result == VK_SUCCESS) {
            GOLOGW("vkCreateSemaphore (acquire) completed successfully for frame %u", i);
        } else {
            GOLOGE("vkCreateSemaphore (acquire) failed with error: %d for frame %u", result, i);
            return;
        }

        result = vkCreateCommandPool(m_device, &poolInfo, nullptr, &fif.commandPool);
        if (result == VK_SUCCESS) {
            GOLOGW("vkCreateCommandPool completed successfully for frame %u", i);
        } else {
            GOLOGE("vkCreateCommandPool failed with error: %d for frame %u", result, i);
            return;
        }

        commandBufferAllocateInfo.commandPool = fif.commandPool;
        result = vkAllocateCommandBuffers(m_device, &commandBufferAllocateInfo, &fif.commandBuffer);
        if (result == VK_SUCCESS) {
            GOLOGW("vkAllocateCommandBuffers completed successfully for frame %u", i);
        } else {
            GOLOGE("vkAllocateCommandBuffers failed with error: %d for frame %u", result, i);
            return;
        }

        char label[256U];
        
        // 使用安全的 snprintf 替换 snprintf_s
        int iRet = std::snprintf(label, sizeof(label), "FiF #%u", i);
        if (iRet < 0 || static_cast<size_t>(iRet) >= sizeof(label)) {
            // 格式化失败或缓冲区不足，使用默认标签
            std::strncpy(label, "FrameInFlight", sizeof(label) - 1);
            label[sizeof(label) - 1] = '\0';  // 确保以null结尾
            GOLOGE("snprintf failed or buffer too small for FiF #%u", i);
        }
        
        OHTestApp::SetLabel(m_device, fif.commandBuffer, VK_OBJECT_TYPE_COMMAND_BUFFER, label);

        result = vkCreateFence(m_device, &fenceInfo, nullptr, &fif.fence);
        if (result == VK_SUCCESS) {
            GOLOGW("vkCreateFence completed successfully for frame %u", i);
        } else {
            GOLOGE("vkCreateFence failed with error: %d for frame %u", result, i);
            return;
        }
    }
}

void HelloVK::FGCreateCommandPool()
{
    OHTestApp::CommandPool::Instance().Init(OHTestApp::CommandPool::CommandPoolDescriptor()
        .Name("CommandPool")
        .Device(m_device)
        .Flags(0U)
        .QueueFamilyIndex(OHTestApp::Device::Instance().GetQueueFamilyIndex())
        .Queue(OHTestApp::Device::Instance().GetNativeQueue()));

    constexpr VkSemaphoreCreateInfo semaphoreInfo {
        .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
        .pNext = nullptr,
        .flags = 0U
    };

    VkCommandPoolCreateInfo const poolInfo {
        .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
        .pNext = nullptr,
        .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
        .queueFamilyIndex = OHTestApp::Device::Instance().GetQueueFamilyIndex()
    };

    constexpr VkFenceCreateInfo fenceInfo {
        .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
        .pNext = nullptr,
        .flags = VK_FENCE_CREATE_SIGNALED_BIT
    };

    VkCommandBufferAllocateInfo commandBufferAllocateInfo {
        .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
        .pNext = nullptr,
        .commandPool = VK_NULL_HANDLE,
        .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
        .commandBufferCount = 1U
    };

    m_framesInFlights.clear();
    m_framesInFlights.resize(OHTestApp::FRAMES_IN_FLIGHT);
    m_writingCommandBufferIdx = 0U;

    CreateCommandPoolResources(semaphoreInfo, poolInfo, fenceInfo, commandBufferAllocateInfo);
}

void HelloVK::FGCreateSwapchainSyncObjects()
{
    size_t const count = m_swapChainImages.size();
    m_swapchainInfo.clear();
    m_swapchainInfo.resize(count);

    constexpr VkSemaphoreCreateInfo semaphoreInfo {
        .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
        .pNext = nullptr,
        .flags = 0U
    };

    for (size_t i = 0; i < count; ++i) {
        auto &info = m_swapchainInfo[i];
        VkResult result = vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &info.renderEnd);
        if (result == VK_SUCCESS) {
            GOLOGW("vkCreateSemaphore (renderEnd) completed successfully for swapchain image %zu", i);
        } else {
            GOLOGE("vkCreateSemaphore (renderEnd) failed with error: %d for swapchain image %zu", result, i);
            return;
        }
    }
}

void HelloVK::FGInitUIRenderer()
{
    OHTestApp::UIRenderer::UIRendererDescriptor desc{};
    desc.frameInFlightNum = OHTestApp::FRAMES_IN_FLIGHT;
    desc.frameBufferNum = m_swapChainImages.size();
    desc.canvasWidth = m_swapChainExtent.width;
    desc.canvasHeight = m_swapChainExtent.height;
    desc.colorFormat = m_swapChainImageFormat;

    for (auto &item : m_swapChainImageViews) {
        desc.colorImageViews.push_back(item);
    }

    OHTestApp::UIRenderer &renderer = OHTestApp::UIRenderer::Instance();
    renderer.Init(desc);

    m_sceneColorBackground = renderer.MakeBackground(m_sceneColor);
    m_predictedColorBackground = renderer.MakeBackground(m_predictedColor);
}

void HelloVK::FGInitMainSceneRenderer()
{
    OHTestApp::MainSceneRenderer &sceneRenderer = OHTestApp::MainSceneRenderer::Instance();

    sceneRenderer.Init(OHTestApp::MainSceneRenderer::MainSceneRendererDescriptor {
        .frameInFlightNum = OHTestApp::FRAMES_IN_FLIGHT,
        .frameBufferNum = OHTestApp::FRAMES_IN_FLIGHT,
        .frameBufferWidth = m_swapChainExtent.width,
        .frameBufferHeight = m_swapChainExtent.height,
        .colorFormat = m_sceneColor.GetFormat(),
        .depthStencilFormat = m_sceneDepthStencil.GetFormat()
    });

    VkImageView const attachments[] = {m_sceneColor.GetNativeImageView(), m_sceneDepthStencil.GetNativeImageView()};

    VkFramebufferCreateInfo framebufferInfo {
        .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
        .pNext = nullptr,
        .flags = 0U,
        .renderPass = sceneRenderer.GetRenderPass(),
        .attachmentCount = static_cast<uint32_t>(std::size(attachments)),
        .pAttachments = attachments,
        .width = m_swapChainExtent.width,
        .height = m_swapChainExtent.height,
        .layers = 1U
    };

    VkResult result = vkCreateFramebuffer(m_device, &framebufferInfo, nullptr, &m_sceneFramebuffer);
    if (result == VK_SUCCESS) {
        GOLOGW("vkCreateFramebuffer completed successfully");
    } else {
        GOLOGE("vkCreateFramebuffer failed with error: %d", result);
    }
}

void HelloVK::FGDestroyUIRenderer()
{
    OHTestApp::UIRenderer::Instance().Destroy();
}

void HelloVK::FGDestroyMainSceneRenderer()
{
    OHTestApp::MainSceneRenderer::Instance().Destroy();
}

void HelloVK::RenderAndUpdateCameraInfo(OHTestApp::MainSceneRenderer &sceneRenderer, FrameInFlight *fif,
    uint8_t fifIndex)
{
    sceneRenderer.Render(fif->commandBuffer, m_sceneFramebuffer, static_cast<size_t>(fifIndex));

    m_viewProj = sceneRenderer.GetSceneViewProjMatrix();
    m_invViewProj = glm::inverse(sceneRenderer.GetSceneViewProjMatrix());
}

void HelloVK::FGBalancedInterRender()
{

    if (!m_window) {
        return;
    }

    if (m_orientationChanged) {
        OnOrientationChange();
    }

    auto const fifIndex = static_cast<uint8_t>(m_writingCommandBufferIdx);
    FrameInFlight *fif = &m_framesInFlights[m_writingCommandBufferIdx];
    UpdateWritingCommandBufferIdx();

    VkResult result = vkWaitForFences(m_device, 1U, &fif->fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
    if (result == VK_SUCCESS) {
        if (!s_loggedWaitForFences) {
            GOLOGW("vkWaitForFences completed successfully");
            s_loggedWaitForFences = true;
        }
    } else {
        GOLOGE("vkWaitForFences failed with error: %d", result);
    }

    ResetStatus(fif);

    VkCommandBufferBeginInfo beginCB = CreateBeginInfo();
    result = vkBeginCommandBuffer(fif->commandBuffer, &beginCB);
    if (result == VK_SUCCESS) {
        if (!s_loggedBeginCommandBuffer) {
            GOLOGW("vkBeginCommandBuffer completed successfully");
            s_loggedBeginCommandBuffer = true;
        }
    } else {
        GOLOGE("vkBeginCommandBuffer failed with error: %d", result);
    }

    OHTestApp::MainSceneRenderer &sceneRenderer = OHTestApp::MainSceneRenderer::Instance();
    sceneRenderer.Update(static_cast<uint32_t>(fifIndex));

    OHTestApp::UIRenderer &uiRenderer = OHTestApp::UIRenderer::Instance();
    uiRenderer.Update(static_cast<uint32_t>(fifIndex));

    // 标准渲染流程：渲染场景 -> 绘制UI -> 显示
    RenderAndUpdateCameraInfo(sceneRenderer, fif, fifIndex);
    uiRenderer.Draw(fif->commandBuffer, m_imageIndex, static_cast<uint32_t>(fifIndex), m_sceneColorBackground);

    result = vkEndCommandBuffer(fif->commandBuffer);
    if (result == VK_SUCCESS) {
        if (!s_loggedEndCommandBuffer) {
            GOLOGW("vkEndCommandBuffer completed successfully");
            s_loggedEndCommandBuffer = true;
        }
    } else {
        GOLOGE("vkEndCommandBuffer failed with error: %d", result);
    }

    InterRealFrameDisplay(fif);
}

VkSubmitInfo HelloVK::CreateSubmitInfo(FrameInFlight *fif, const VkPipelineStageFlags &waitStage)
{
    VkSubmitInfo submitInfo{};
    submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    submitInfo.waitSemaphoreCount = 1U;
    submitInfo.pWaitSemaphores = &fif->acquire;
    submitInfo.pWaitDstStageMask = &waitStage;
    submitInfo.commandBufferCount = 1U;
    submitInfo.pCommandBuffers = &fif->commandBuffer;
    submitInfo.signalSemaphoreCount = 1U;
    submitInfo.pSignalSemaphores = &m_swapchainInfo[m_imageIndex].renderEnd;
    return submitInfo;
}

VkPresentInfoKHR HelloVK::CreatePresentInfo(VkResult &presentResult)
{
    VkPresentInfoKHR presentInfo{};
    presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
    presentInfo.waitSemaphoreCount = 1U;
    presentInfo.pWaitSemaphores = &m_swapchainInfo[m_imageIndex].renderEnd;
    presentInfo.swapchainCount = 1U;
    presentInfo.pSwapchains = &m_swapChain;
    presentInfo.pImageIndices = &m_imageIndex;
    presentInfo.pResults = &presentResult;
    return presentInfo;
}

void HelloVK::InterRealFrameDisplay(FrameInFlight *fif)
{
    // 标准Vulkan显示流程
    constexpr VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    
    VkSubmitInfo const submitInfo = CreateSubmitInfo(fif, waitStage);
    VkResult result = vkQueueSubmit(m_graphicsQueue, 1U, &submitInfo, fif->fence);
    if (result == VK_SUCCESS) {
        if (!s_loggedQueueSubmit) {
            GOLOGW("vkQueueSubmit completed successfully");
            s_loggedQueueSubmit = true;
        }
    } else {
        GOLOGE("vkQueueSubmit failed with error: %d", result);
    }

    VkResult presentResult = VK_SUCCESS;
    VkPresentInfoKHR const presentInfo = CreatePresentInfo(presentResult);
    Present(presentInfo);
}

void HelloVK::UpdateWritingCommandBufferIdx()
{
    m_writingCommandBufferIdx = (m_writingCommandBufferIdx + 1U) % OHTestApp::FRAMES_IN_FLIGHT;
}

VkCommandBufferBeginInfo HelloVK::CreateBeginInfo()
{
    VkCommandBufferBeginInfo beginInfo{};
    beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
    beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
    return beginInfo;
}

void HelloVK::ResetStatus(FrameInFlight *fif)
{
    VkResult result = vkResetFences(m_device, 1U, &fif->fence);
    if (result == VK_SUCCESS) {
       
        if (!s_loggedResetFences) {
            GOLOGW("vkResetFences completed successfully");
            s_loggedResetFences = true;
        }
    } else {
        GOLOGE("vkResetFences failed with error: %d", result);
    }

    result = vkResetCommandPool(m_device, fif->commandPool, 0U);
    if (result == VK_SUCCESS) {
        if (!s_loggedResetCommandPool) {
            GOLOGW("vkResetCommandPool completed successfully");
            s_loggedResetCommandPool = true;
        }
    } else {
        GOLOGE("vkResetCommandPool failed with error: %d", result);
    }

    Acquire(fif->acquire);
}

void HelloVK::ResetStatus(FrameInFlight *fif, VkCommandBufferBeginInfo &beginCB)
{
    ResetStatus(fif);
    VkResult result = vkBeginCommandBuffer(fif->commandBuffer, &beginCB);
    if (result == VK_SUCCESS) {
        if (!s_loggedBeginCommandBuffer) {
            GOLOGW("vkBeginCommandBuffer completed successfully");
            s_loggedBeginCommandBuffer = true;
        }
    } else {
        GOLOGE("vkBeginCommandBuffer failed with error: %d", result);
    }
}
}
